package com.starry.module.system.core.file.client.s3;

import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.starry.module.system.core.file.client.AbstractFileClient;
import com.starry.module.system.core.file.client.domain.UploadSuccessDto;
import com.starry.module.system.core.file.entity.FileConfig;

import java.io.ByteArrayInputStream;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.UUID;

/**
 * S3客户端
 *
 * @author xiaoke
 */
public class S3FileClient extends AbstractFileClient {


    private AmazonS3Client client;


    public S3FileClient(Long id, FileConfig config) {
        super(config);
    }

    @Override
    protected void doInit() {
        // 补全 domain
        if (StrUtil.isEmpty(config.getDomain())) {
            config.setDomain(buildDomain());
        }
        // 初始化客户端
        client = (AmazonS3Client) AmazonS3ClientBuilder.standard()
                .withCredentials(buildCredentials())
                .withEndpointConfiguration(buildEndpointConfiguration())
                .build();
    }

    @Override
    public UploadSuccessDto upload(byte[] content, String originalFileName, String type) throws Exception {
        // 元数据，主要用于设置文件类型
        ObjectMetadata objectMetadata = new ObjectMetadata();
        objectMetadata.setContentType(type);
        // 如果不设置，会有 “ No content length specified for stream data” 警告日志
        objectMetadata.setContentLength(content.length);
        UploadSuccessDto uploadSuccess = new UploadSuccessDto();
        // 如果文件名中不包含 / 就使用日期文件夹存储
        if (!originalFileName.contains("/")) {
            uploadSuccess = getPath(originalFileName);
        } else {
            uploadSuccess.setFileName(originalFileName);
            uploadSuccess.setFilePath(originalFileName);
        }
        // 执行上传
        client.putObject(
                config.getBucket(), // bucket
                uploadSuccess.getFilePath(), // 相对路径
                new ByteArrayInputStream(content), // 文件内容
                objectMetadata
        );
        // 拼接返回路径
        uploadSuccess.setFileUrl(config.getDomain() + "/" + uploadSuccess.getFilePath());
        uploadSuccess.setConfigId(config.getId());
        uploadSuccess.setBucket(config.getBucket());

        return uploadSuccess;
    }

    @Override
    public void delete(String path) throws Exception {

    }

    @Override
    public byte[] getContent(String path) throws Exception {
        return new byte[0];
    }


    private UploadSuccessDto getPath(String originalFileName) {
        LocalDate currentDate = LocalDate.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        String dateStr = currentDate.format(formatter);
        //获取扩展名
        String fileExtension = originalFileName.substring(originalFileName.lastIndexOf("."));
        String fileName = UUID.randomUUID().toString() + fileExtension;

        UploadSuccessDto uploadSuccessDto = new UploadSuccessDto();
        uploadSuccessDto.setFileName(fileName);
        uploadSuccessDto.setFilePath(dateStr + "/" + fileName);
        return uploadSuccessDto;
    }

    /**
     * 基于 bucket + endpoint 构建访问的 Domain 地址
     *
     * @return Domain 地址
     */
    private String buildDomain() {
        // 如果已经是 http 或者 https，则不进行拼接.主要适配 MinIO
        if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) {
            return StrUtil.format("{}/{}", config.getEndpoint(), config.getBucket());
        }
        // 阿里云、腾讯云、华为云都适合。七牛云比较特殊，必须有自定义域名
        return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint());
    }

    /**
     * 基于 config 秘钥，构建 S3 客户端的认证信息
     *
     * @return S3 客户端的认证信息
     */
    private AWSStaticCredentialsProvider buildCredentials() {
        return new AWSStaticCredentialsProvider(
                new BasicAWSCredentials(config.getAccessKey(), config.getAccessSecret()));
    }

    /**
     * 构建 S3 客户端的 Endpoint 配置，包括 region、endpoint
     *
     * @return S3 客户端的 EndpointConfiguration 配置
     */
    private AwsClientBuilder.EndpointConfiguration buildEndpointConfiguration() {
        return new AwsClientBuilder.EndpointConfiguration(config.getEndpoint(),
                null); // 无需设置 region
    }
}
